package javaer.dev.manual.depthclone;

import org.apache.commons.lang3.SerializationUtils;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 测试
 */
public class CloneTest {
    /**
     * 使用 JSON 序列化
     */
    @Test
    public void deepCloneByJSON() {
        // Obj -> JSON -> Obj
    }

    /**
     * 使用 commons-lang3 包
     */
    @Test
    public void deepCloneByCommonslang3() {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        Order order = OrderMocker.mock();
        order.setOrderNo("first");
        executorService.execute(() -> doSomeThing(order));

        Order cloneOrder = SerializationUtils.clone(order);

        cloneOrder.setOrderNo("second");
        executorService.execute(() -> doSomeThing(order));
    }

    /**
     * JDK 序列化方式深拷贝
     */
    @Test
    public void  deepCloneByIO() throws IOException, ClassNotFoundException {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        Order order = OrderMocker.mock();
        order.setOrderNo("first");
        executorService.execute(() -> doSomeThing(order));

        Order cloneOrder = CloneUtil.deepClone(order);
        cloneOrder.setOrderNo("second");
        executorService.execute(() -> doSomeThing(order));

        // debugger 可以看到 clone 后是一个全新的对象 {Order@1574}   {Order@1575}
    }


    /**
     * 手动深拷贝
     */
    @Test
    public void cloneByHand() {
        Order or = OrderMocker.mock();
        Order cloneOrder = (Order) or.clone();

        System.err.println(or == cloneOrder);  // false
        // ItemList 没有深度拷贝
        System.err.println(or.getItemList() == or.getItemList());      // true

    }

    /**
     * 多线程中,
     * 不通过克隆新对象, 线程池中的线程共用同一个对象, 后面修改影响到其他线程
     */
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        Order order = OrderMocker.mock();
        order.setOrderNo("first");
        executorService.execute(() -> doSomeThing(order));

        order.setOrderNo("second");
        executorService.execute(() -> doSomeThing(order));

    }

    /**
     * 只用一个主线程
     * 就不存在共享问题
     */
    public static void main1(String[] args) {
        Order order = OrderMocker.mock();

        order.setOrderNo("first");
        doSomeThing(order);
        order.setOrderNo("second");
        doSomeThing(order);

    }

    public static void doSomeThing(Order order) {
        try {
            TimeUnit.SECONDS.sleep(1L);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("do some thing: " + order.getOrderNo());
    }
}
